<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import request from '../utils/request'
import axios from 'axios'
import HelloWorld from './components/HelloWorld.vue'

import { ref, isRef } from 'vue'
import FileSplitWorker from './filesplit.worker.js?worker'
// import LeftTable from '../../../element-plus/packages/components/table-v2/src/renderers/right-table'
const worker = new FileSplitWorker()
console.log(worker)

let fileList = ref([])
let cancelerMap = {}
function splitFileChunk(files, callback) {
  worker.postMessage({
    // 每一个切片的大小
    chunkSize: 1 * 1024 * 1024,
    files: files,
  })
  worker.onmessage = (file) => {
    // console.log(file)
    callback && callback(file)
  }
}
// 并发控制函数
async function asyncPool(poolLimit, array, iteratorFn, {ret = [], executing = [], p = null}) {
  for (const item of array) {
    p = Promise.resolve().then(() => {
      return iteratorFn(item, array)
    });
    ret.push(p);

    if (poolLimit <= array.length) {
      const e = p.then(() => {
        return executing.splice(executing.indexOf(e), 1)
      });
      executing.push(e);
      if (executing.length >= poolLimit) {
        await Promise.race(executing.map((item)=>{
          return item.catch((error)=>{
            return error
          })
        }));
      }
    }
  }

  return Promise.all(ret.map(item=>{
      return item.catch(error => {
        return error
      })
    }))
}
async function onFileChange(e) {
  const files = Array.from(e.target.files || [])

  splitFileChunk(files, (fileSplitObject) => {
    fileSplitObject.data.loaded = 0
    fileSplitObject.data.complete = ref(0)
    fileList.value.push(fileSplitObject.data)
    if (fileList.value.length >= fileSplitObject.data.filesLength) {
      console.log('file split done!')
    }
  })
}
async function upload(fileList) {
  const requestList = []
  
  if(!isRef(fileList)) {
    fileList.value = fileList
  }
  
  fileList.value.forEach(async (data) => {
    const chunkIds =(await getUploadChunksIds(data.fileHash)).data.data
    console.log(chunkIds)
    let rdata = data
    data.uploadStatus = true

    requestList.push(asyncPool(1, [...data.chunks.keys()], (i) => {
      
      if (chunkIds.includes(i+'')) {
        data.loaded=chunkIds.length
        updateProgress(data.fileHash, 0)
        return Promise.resolve()
      }
      return upLoadChunk(rdata.chunks[i], rdata.name, rdata.fileType, rdata.chunkTotal, data)
    }))
  })

  return asyncPool(1, [...requestList], async (item)=>{
    await item
  })
}
async function getUploadChunksIds(hash) {
  return await request({
    url: '/more/getUploadChunks',
    method: 'post',
    data: {
      hash
    }
  })
}
async function upLoadChunk(chunk, filename, filetype, chunkTotal, file) {
  if(!file.uploadStatus) {
    return Promise.reject()
  }
  const formData = new FormData()
  // console.log(chunk.chunk)
  formData.set('file', chunk.chunk, filename)
  formData.set('id', chunk.id)
  formData.set('hash', chunk.parentHash)
  formData.set('type', filetype)
  formData.set('total', chunkTotal)
  
  await request({
    url: '/more/upload/single',
    headers: {
      'Conection': 'keep-alive'
    },
    timeout: 24 * 60 * 60 * 1000,
    method: 'post',
    data: formData,
    contentType: false,
    processData: false,
    cancelToken: new axios.CancelToken((cancel)=>{
      cancelerMap[chunk.parentHash] ? (cancelerMap[chunk.parentHash].push(cancel) ): (cancelerMap[chunk.parentHash] = [cancel]);
      // console.log(cancelerMap)
    })
  })
  updateProgress(chunk.parentHash)
}
function updateProgress(hash, temp = 1) {
  let index = fileList.value.findIndex((_file) => _file.fileHash === hash)
  if (index > -1) {
    let item = fileList.value[index]
    item.loaded += temp
    if(parseFloat(item.loaded / item.chunkTotal, 10).toFixed(2) <= 1) {
      item.complete = parseFloat(item.loaded / item.chunkTotal, 10).toFixed(1)
    } else {
      item.complete = 1.0
    }
  }
}
function uploadSinlgBigFile(file) {
    upload([file])
}
async function startUpload() {
  upload(fileList)
}
function toggleUpload (file) {
  if(file.uploadStatus) {
    stopUpload(file)
  } else {
    uploadSinlgBigFile(file)
  }
}
function stopUpload (file) {
  // 取消未上传的切片
  file.uploadStatus = false
  // 取消正在pending的切片
  cancelerMap[file.fileHash].forEach((cancel)=>{
    cancel()
  })
}
function removeFile(file) {
  fileList.value.splice(fileList.value.findIndex((_f) => _f === file), 1)
}
function stopAllUpload() {
  fileList.value.forEach((file)=>{
    stopUpload(file)
  })
}
</script>

<template>
  <div>
    <input type="file" multiple="multiple" name="filename" @change="onFileChange">
    <input type="button" value="上传" @click="startUpload">
    <input type="button" @click="stopAllUpload" value="取消上传">
  </div>
  <div class="upload-list">
    <table class="">
      <thead>
        <th>
        <td>name</td>
        <td>progress</td>
        </th>
      </thead>
      <tbody v-if="fileList.length">
        <tr v-for="file in fileList" :key="file.name">
          <td>{{ file.name }}</td>
          <td>{{ file.complete }}</td>
          <td class="cancel"><input type="button" value="cancel" @click="toggleUpload(file)"></td>
          <td><input type="button" value="remove" @click="removeFile(file)"></td>
        </tr>
      </tbody>
    </table>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}

.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}

.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
